package models;
import java.io.*;
import java.net.*;
import java.util.HashMap;
import java.util.Map;

import models.msgs.Join;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;

import play.mvc.*;
import play.libs.*;
import scala.concurrent.Await;
import scala.concurrent.duration.Duration;
import akka.actor.*;
import static akka.pattern.Patterns.ask;
import static java.util.concurrent.TimeUnit.SECONDS;

/**class to controls all clients*/
public class ManagerOfClients extends UntypedActor {
    /** List of Clients */
	private static Player [] clients;
	/** numeber of connected client */
	private static int number;
	private Deck deck;
	private Game game;
	
	private static int startingCoins = 500;
	
	private static int smallBlind = 20;
	
	private static int bigBlind= 50;
	
	private boolean rejecting;
	
	private int rejectingPlayer;
	
	private boolean start;
	
	private int port;
	
	private int BotNumber;
	
	/** Default Manager	 */
    static ActorRef defaultManager = Akka.system().actorOf(Props.create(ManagerOfClients.class));
    /** Players */
    static Map<String, ActorRef> members = new HashMap<String, ActorRef>();
	/**constructor.*/
	/**
	* @param startingCoins coins at the start
	* @param smallBlind smallBlind
	* @param bigBlind bigBlind
	* @param port server
	*/
	public ManagerOfClients()
	{
		start =false;
		this.rejecting =false;
		this.game =null;
		this.clients = new Player[6];
		int number = 0;
		this.rejectingPlayer = -1;
		this.BotNumber = 1;
	}
	/**Method adds new CLient*/
	public static void addNewClient(final String name, WebSocket.In<JsonNode> in, WebSocket.Out<JsonNode> out )throws Exception
	{
		if(number < 6)
		{
			if(clients == null)
				{
					clients = new Player[6];
					System.out.println("dziwne");
				}
			for(int i = 0; i<6; i++)
		    {
				
		    		if(clients[i] == null)
		    		{
			
		    			String result = (String)Await.result(ask(defaultManager,new Join(name), 1000), Duration.create(1, SECONDS));
		    			if("OK".equals(result)) {
		        	
						Player player = new Player(i, name, startingCoins);
	    				ActorRef playerConnection =  Akka.system().actorOf(
		    	                    Props.create(ServerConnection.class,in, out, defaultManager, player));
                           

                           
                           members.put(name, playerConnection);
                           number++;
                           String text =  "Number_" + number; 
                           System.out.println(number); 
                           notifyAll(new Info(text,name)); 
                           clients[i] = player;
                           	break;
			  }
			}
		    }
		}
		else
		{
			/*ServerConnection tmpConnection = new ServerConnection(socket,this);
			tmpConnection.send("ERROR_"+"Too many player in game");*/
		}

	}
	/** Method send data too all connected client */
	public void sendToAllClients( String data)
	{
		for( int i = 0; i<6; i++)
		{
			if(clients[i] != null)
			{
				clients[i].send(data);
			}
		}
	}
	/** Refresh clients list on client side. */
	public void refreshClientsList()
	{
		String data = new String();
		for(int i = 0; i<6; i++)
		{
			if(clients[i] != null)
			{
				data = data  +clients[i].getNick()+" ";

			}
		}
		
		this.sendToAllClients("ClientList_" + data);
	}
	
	public int numberOfPlayers()
	{
		return (number);
	}
	public int getStartingCoins()
	{
		return this.startingCoins;
	}
	public int getSmallBlind()
	{
		return this.smallBlind;
	}
	public int getBigBlind()
	{
		return this.bigBlind;
	}
	
	public Player[] getClients()
	{
		Player players[] = new Player[number];
		int j = 0;
		for(int i=0; i<6; i++)
		{
			if(this.clients[i] != null)
			{
				players[j] =this.clients[i];//sprawdz
				j++;
			}
		}
		return players;
	}
	
	public void startGame(int n)
	{
		int m = 0;
		for(int i =0; i<6; i++)
		{
			if(clients[i] != null)
				if(clients[i].getReady())
					m++;
				else
				   clients[i].send("Chat_ Players: "+clients[n].getNick() + " is ready to start");
		}
		if (m==number)
		{
			this.sendToAllClients("GameStart_");
			if(game == null)
				{
				deck = new Deck();
			
			    this.game = new Game(this, deck);
				}
			for(int i =0; i<6; i++)
			{
				if(clients[i] != null)
				{
					clients[i].startGame(game, deck);
				}
				
			}
			start =true;
			game.startGame();
		}
		else
		{
			clients[n].send("WaitForPlayers_");
		}
			
		}
	
	public void deleteClient(int n)
	{
		if(clients[n] != null)
			clients[n].kill();
		clients[n] = null;
        this.number =number-1;
		
		if(start)
		{
			game.deletePlayer(n);
			this.sendToAllClients("Fold_"+n);
		}
		else
		{
			
			Player[] tmpclients;
			tmpclients = this.getClients();
			for(int i=0; i<tmpclients.length; i++)
			{	System.out.println(i);
				this.clients[i] = tmpclients[i];
				clients[i].setNumber(i);
				this.clients[i].send("Number_"+i);
			
				
			}
			for(int i=tmpclients.length; i<6; i++)
			{	
				this.clients[i] = null;
			}
			this.refreshClientsList();
		}
	}

	//only if game is not started !!
	public void rejectPlayer(int rejected, int rejection)
	{
		if(!rejecting||game ==null)
		{rejectingPlayer = rejected;
		for(int i=0; i<6;i++)
		{
			if(i!=rejection&&i!=rejected&&clients[i]!=null)
				clients[i].rightToVote = true;
		}
		System.out.println(rejected);
		
		
		this.sendToAllClients("proposalToReject_" + clients[rejected].getNumber());
		this.reject(1);
		rejecting = true;
		
		}
		else
		{
			clients[rejected].send("Wait_");
		}
	}
	public void reject(int vote)
	{
		System.out.println("rejected" +rejectingPlayer );
		if(vote == 1)
		{System.out.println(vote);
			
			clients[rejectingPlayer].voteForRejection++;
			if(clients[rejectingPlayer].voteForRejection > number-2)
			{
				System.out.println("PlayerRejecting_" + clients[rejectingPlayer].getNumber());
				
				this.sendToAllClients("PlayerRejecting_" + clients[rejectingPlayer].getNumber());
				for(int i = rejectingPlayer; i<6;i++)
				{
					if(this.clients[i]!=null)
					{
						this.clients[i].send("Number_"+(i-1));
					}
				}
				deleteClient(rejectingPlayer);
				rejecting =false;
				rejectingPlayer =-1;
				for(int i=0; i<6;i++)
				{
					if(i!=rejectingPlayer&&clients[i]!=null)
						clients[i].rightToVote = false;
				}
			}
		}
		else
		{System.out.println(vote);
			System.out.println("PlayerNotRejecting_" + clients[rejectingPlayer].getNumber());
			this.sendToAllClients("PlayerNotRejecting_" + clients[rejectingPlayer].getNumber());
			rejecting = false;
			for(int i=0; i<6;i++)
			{
				if(i!=rejectingPlayer&&clients[i]!=null)
					clients[i].rightToVote = false;
			}
			clients[rejectingPlayer].voteForRejection = 0;
		}
		
	}
	public void addBot()
	{
        Runtime r=Runtime.getRuntime();
        try
        {
            r.exec("java Bot "+port+" localhost "+"Bot"+BotNumber);
        }
        catch(Exception e)
        {
            System.out.println(e.toString());
        }
        BotNumber++;
        
        if(BotNumber<0)
        	BotNumber = 1;
	}
public void stopGame()
{
	start =false;
	for(int i=0; i<6; i++)
	{
		if(clients[i]!= null)
		{
			clients[i].stopGame();
		}
	}
	sendToAllClients("Stop_");

	this.refreshClientsList();
	Player[] tmpclients;
	tmpclients = this.getClients();
	for(int i=0; i<tmpclients.length; i++)
	{	System.out.println(i);
		this.clients[i] = tmpclients[i];
		clients[i].setNumber(i);
		this.clients[i].send("Number_"+i);	
		
	}
	for(int i=tmpclients.length; i<6; i++)
	{	
		this.clients[i] = null;
	}
}

public void onReceive(Object message) throws Exception {
    
	if (message instanceof SendToAllClients)
	{
		SendToAllClients sendToAllClients = (SendToAllClients)message;
		this.sendToAllClients(sendToAllClients.getMessage());
	}
	else if(message instanceof Join) {
          
          Join join = (Join) message;
                      
          if(false){
          	// if username is already taken do sth        	
          }
          else {                
              getSender().tell("OK", getSelf());
          }
      }
	else if( message instanceof RejectPlayer )
	{
		RejectPlayer rejectPlayer = (RejectPlayer) message;
		this.rejectPlayer(rejectPlayer.getRejected(), rejectPlayer.getRejection());
	}
	else if(message instanceof RefreshClientsList)
	{
		this.refreshClientsList();
	}	
	else if(message instanceof StartGame)
	{
		StartGame startGame = (StartGame) message;
		this.startGame( startGame.getNumber());
	}
	else if(message instanceof Reject)
	{
		Reject reject = (Reject) message;
		this.startGame( reject.getVote());
	}
	else if(message instanceof AddBot)
	{
		this.addBot();
	}
    else if (message instanceof Info)
    {   
    	String text = ((Info) message).getText();
    	String name = ((Info) message).getName();  
    	
    	notifyAll(new Info(text, name));
    } 
    else if(message instanceof Quit)  {            
        
        String name = ((Quit)message).getName();            
        members.remove(name);
        String text = "has left the game";            		
        notifyAll(new Info(text, name));
    }
	else
	unhandled(message);
    
}
static public void notifyAll(Object msg)
{
    for (ActorRef member : members.values())
    {
        member.tell(msg, defaultManager);
    }
}
}
